using System;
using dnAnalytics.LinearAlgebra;
using NUnit.Framework;

namespace dnAnalytics.Tests.LinearAlgebra
{
    [TestFixture]
    public class SparseVectorTest : VectorTest
    {
        public override Vector GetVector(int order)
        {
            return new SparseVector(order);
        }

        public override Vector GetVector(int order, double value)
        {
            return new SparseVector(order, value);
        }

        public override Vector GetVector(double[] data)
        {
            return new SparseVector(data);
        }

        public override Matrix GetMatrix(int rows, int columns)
        {
            return new DenseMatrix(rows, columns);
        }

        // NOTE: bug-fix tests. 
        // Bug-behavior: The sparse vector would not find the maximum value if the first entry in the sparse array was the maximum
        // Cause: An index error (starting at the second entry in the sparse array).

        [Test]
        public void MaximumWithMaximumOnFirstEntry()
        {
            Vector vector = GetVector(2000);
            vector[1845] = 38;
            vector[1857] = 25;
            vector[1957] = 25;

            Assert.AreEqual(1845, vector.MaximumIndex());
            Assert.AreEqual(38, vector.Maximum());
        }

        // NOTE: bug-fix tests. 
        // Bug-behavior: The sparse vector would not find the minimum value if the first entry in the sparse array was the minimum
        // Cause: An index error (starting at the second entry in the sparse array).

        [Test]
        public void MinimumWithMinimumOnFirstEntry()
        {
            Vector vector = GetVector(2000);
            vector[1845] = 15;
            vector[1857] = 25;
            vector[1957] = 25;

            Assert.AreEqual(1845, vector.MinimumIndex());
            Assert.AreEqual(15, vector.Minimum());
        }

        [Test]
        public void SparseOperatorSubtract()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = new SparseVector(testArray);
            SparseVector result = vector1 - vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] - vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorSubtractNull1()
        {
            SparseVector vector = new SparseVector(testArray);
            SparseVector result = vector - null;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorSubtractNull2()
        {
            SparseVector vector = new SparseVector(testArray);
            SparseVector result = null - vector;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SparseOperatorSubtractVectorVectorNonConformable()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = new SparseVector(vector1.Count + 1);
            SparseVector result = vector1 - vector2;
        }

        [Test]
        public void SparseOperatorNegate()
        {
            SparseVector SparseVector = new SparseVector(testArray);
            SparseVector result = -SparseVector;
            Assert.AreEqual(SparseVector.Count, result.Count);
            for (int i = 0; i < SparseVector.Count; i++)
            {
                Assert.AreEqual(-SparseVector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorNegateNull()
        {
            SparseVector SparseVector = null;
            SparseVector = -SparseVector;
        }

        [Test]
        public void SparseOperatorAdd()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = new SparseVector(testArray);
            SparseVector result = vector1 + vector2;
            Assert.AreEqual(vector1.Count, result.Count);
            for (int i = 0; i < vector1.Count; i++)
            {
                Assert.AreEqual(vector1[i] + vector2[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorAddNull1()
        {
            SparseVector vector = new SparseVector(testArray);
            SparseVector result = vector + null;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorAddNull2()
        {
            SparseVector vector2 = new SparseVector(testArray);
            SparseVector result = null + vector2;
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void SparseOperatorAddNonConformable()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = new SparseVector(vector1.Count + 1);
            SparseVector result = vector1 + vector2;
        }

        [Test]
        public void SparseOperatorPlus()
        {
            SparseVector SparseVector = new SparseVector(testArray);
            SparseVector result = +SparseVector;
            Assert.AreEqual(SparseVector.Count, result.Count);
            for (int i = 0; i < SparseVector.Count; i++)
            {
                Assert.AreEqual(+SparseVector[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorPlusNull()
        {
            SparseVector SparseVector = null;
            SparseVector = +SparseVector;
        }

        [Test]
        public void SparseOperatorMultiplyScalarVector()
        {
            SparseVector SparseVector = new SparseVector(testArray);
            double scalar = 2.2;
            SparseVector result = scalar * SparseVector;
            Assert.AreEqual(SparseVector.Count, result.Count);
            for (int i = 0; i < testArray.Length; i++)
            {
                Assert.AreEqual(scalar * testArray[i], result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorMultiplyScalarVectorNull()
        {
            SparseVector SparseVector = null;
            double scalar = 2.2;
            SparseVector result = scalar * SparseVector;
        }

        [Test]
        public void SparseOperatorMultiplyVectorScalar()
        {
            SparseVector SparseVector = new SparseVector(testArray);
            double scalar = 2.2;
            SparseVector result = SparseVector * scalar;
            Assert.AreEqual(SparseVector.Count, result.Count);
            for (int i = 0; i < SparseVector.Count; i++)
            {
                Assert.AreEqual(SparseVector[i] * scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorMultiplyVectorNullScalar()
        {
            SparseVector SparseVector = null;
            double scalar = 2.2;
            SparseVector result = SparseVector * scalar;
        }

        [Test]
        public void SparseOperatorMultiply()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = new SparseVector(testArray);
            Matrix result = vector1 * vector2;
            Assert.AreEqual(vector1.Count, result.Rows);
            Assert.AreEqual(vector2.Count, result.Columns);
            for (int i = 0; i < vector1.Count; i++)
            {
                for (int j = 0; j < vector2.Count; j++)
                {
                    Assert.AreEqual(vector1[i] * vector2[j], result[i, j]);
                }
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorMultiplyNull1()
        {
            SparseVector vector1 = new SparseVector(testArray);
            SparseVector vector2 = null;
            Matrix result = vector1 * vector2;
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorMultiplyNull2()
        {
            SparseVector vector1 = null;
            SparseVector vector2 = new SparseVector(testArray);
            Matrix result = vector1 * vector2;
        }

        [Test]
        public void SparseOperatorDivide()
        {
            SparseVector SparseVector = new SparseVector(testArray);
            double scalar = 2.2;
            SparseVector result = SparseVector / scalar;
            Assert.AreEqual(SparseVector.Count, result.Count);
            for (int i = 0; i < SparseVector.Count; i++)
            {
                Assert.AreEqual(SparseVector[i] / scalar, result[i]);
            }
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void SparseOperatorDivideNull()
        {
            SparseVector SparseVector = null;
            double scalar = 2.2;
            SparseVector result = SparseVector / scalar;
        }
    }
}